package com.zlsy.thread.threadsafe;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zhouliang
 * @date 2020/03/18
 **/
@Slf4j
public class MutilateThreadErrorByNothing implements Runnable {

    int index = 0;
    private CountDownLatch latch;
    private int n;

    final boolean[] marked = new boolean[1000000];
    static AtomicInteger realIndex = new AtomicInteger();
    static AtomicInteger wrongCount = new AtomicInteger();
    volatile CyclicBarrier cyclicBarrier1 = new CyclicBarrier(2);
    volatile CyclicBarrier cyclicBarrier2 = new CyclicBarrier(2);


    public MutilateThreadErrorByNothing(CountDownLatch latch, int n) {
        this.latch = latch;
        this.n = n;
    }


    public static void main(String[] args) throws InterruptedException {
        int n = 10000;
        CountDownLatch latch = new CountDownLatch(n * 2);
        MutilateThreadErrorByNothing instance = new MutilateThreadErrorByNothing(latch, n);

        Thread thread = new Thread(instance);
        Thread thread1 = new Thread(instance);
        thread.start();
        thread1.start();
        latch.await();

        log.info("表面上得出的结果：{}", instance.index);
        log.info("真正运行的次数:{}", realIndex);
        log.info("错误次数:{}", wrongCount);

    }

    @Override
    public void run() {
        for (int i = 0; i < n; i++) {
            try {
                index++;
                //真正运行的次数
                realIndex.incrementAndGet();

                //和MutilateThreadError比起来,我们没在index++的前后控制两个线程同时进行index++,然后都执行完index++才出来.
                //所以我们到这里一定是大于等于两个线程的，假如三个进行了index++，
                //必然会有一个抢到锁，进入代码块把当前内存的index 设置为ture，
                //如果其他线程进去看到的index是当前这个设置的index，那么就会被记录发生错误的次数。
                //但是这个wrongCount总是小于10000的。
                synchronized (this) {
                    if (marked[index]) {
                        //发生错误的次数
                        wrongCount.incrementAndGet();
                    }
                    marked[index] = true;
                }
            } finally {
                latch.countDown();
            }
        }
    }
}
